#pragma once

#include <iostream>

namespace template_method {
    
/// @brief 抽象类, 给出一个算法的轮廓和骨架
class AbstractClass {
public:
    virtual ~AbstractClass() {}

    /// @brief 模板方法, 定义了算法的骨架，按某种顺序调用其包含的基本方法
    virtual void TemplateMethod() {
        SpecificMethodA();
        if (HookMethodB()) {
            HookMethodA();
        }
        AbstractMethod();
        SpecificMethodB();
    }

protected:
    /// @brief 基本方法, 可以有三种
    ///             - 抽象方法：在抽象类中申明，由具体子类实现
    ///             - 具体方法：在抽象类中已经实现，在具体子类中可以继承或重写它
    ///             - 钩子方法：在抽象类中已经实现，包括用于判断的逻辑方法和需要子类重写的空方法两种
    virtual void AbstractMethod() = 0;
    virtual void SpecificMethodA() {
        printf("this is AbstractClass::SpecificMethodA!\n");
    }
    virtual void SpecificMethodB() {
        printf("this is AbstractClass::SpecificMethodB!\n");
    }
    virtual void HookMethodA() {    // 通常为空实现
        printf("this is AbstractClass::HookMethodA!\n");
    }
    virtual bool HookMethodB() { return false; }
};

/// @brief 具体类, 实现抽象类中所定义的抽象方法和钩子方法
class ConcreteClass : public AbstractClass {
public:
    virtual void AbstractMethod() {
        printf("this is ConcreteClass::AbstractMethod!\n");
    }

protected:
    virtual void SpecificMethodB() {
        printf("this is ConcreteClass::SpecificMethodB!\n");
    }
    virtual void HookMethodA() {    // 通常为空实现
        printf("this is ConcreteClass::HookMethodA!\n");
    }
    virtual bool HookMethodB() { return true; }
};

} // namespace template_method

void Test_13_template_method_impl_1() {
    printf("-------------------- %s --------------------\n", __FUNCTION__);
    template_method::AbstractClass* ptr = new template_method::ConcreteClass();
    ptr->TemplateMethod();

    delete ptr;
}

// -------------------- Test_13_template_method_impl_1 --------------------
// this is AbstractClass::SpecificMethodA!
// this is ConcreteClass::HookMethodA!
// this is ConcreteClass::AbstractMethod!
// this is ConcreteClass::SpecificMethodB!